package hostlink

import (
	"encoding/binary"
	"encoding/hex"
	"errors"
	"math"
	"sort"
	"strconv"
	"time"

	"gitee.com/acquisition_driver_development/magus_iot/magus/logs"
)

//默认最大100个寄存器
var anaGroupSize = 100

//hostlink主结构
type Master struct {
	PointArray []*Point
	GroupArray []*Group
}

//hostlink点组结构
type Group struct {
	pointArray []*Point

	NodeNum      string //cpu 单元
	WordCode     string //软元件区
	BeginAddress uint32
	IfBite       bool //开关
	IfString     bool //字符串

	BeginBit byte
	Size     int
}

//初始化
func (this *Master) Initialize() (err error) {
	this.PointArray = make([]*Point, 0)
	this.GroupArray = make([]*Group, 0)
	return
}

//添加点
func (this *Master) AddPoint(point *Point) {
	if point != nil {
		this.PointArray = append(this.PointArray, point)
	}
}

//分组
func (this *Master) InitGroup() (err error) {

	//先排序
	sort.Sort(this)
	//分组
	group := new(Group)
	for _, point := range this.PointArray {
		err := group.AddPoint(point)
		if err != nil {
			if group.GetCount() > 0 {
				this.GroupArray = append(this.GroupArray, group)
				group = new(Group)
				err = group.AddPoint(point)
			}
		}
	}
	if group.GetCount() > 0 {
		this.GroupArray = append(this.GroupArray, group)
	}
	return
}

func (this *Master) Len() int {
	return len(this.PointArray)
}

func (this *Master) Less(i, j int) bool {
	if this.PointArray[i].WordCode == this.PointArray[j].WordCode {
		if this.PointArray[i].Address == this.PointArray[j].Address {
			return this.PointArray[i].Bit < this.PointArray[j].Bit
		}
		return this.PointArray[i].Address < this.PointArray[j].Address
	}
	return this.PointArray[i].WordCode < this.PointArray[j].WordCode
}

func (this *Master) Swap(i, j int) {
	this.PointArray[i], this.PointArray[j] = this.PointArray[j], this.PointArray[i]
}

//==========================Group===============================================

//添加点
func (g *Group) AddPoint(point *Point) (err error) {
	var maxsize int
	if len(g.pointArray) == 0 {
		g.WordCode = point.WordCode
		g.BeginAddress = point.Address
		g.IfBite = point.IfBit
		g.BeginBit = point.Bit
	}
	if g.WordCode != point.WordCode {
		return errors.New("word code of function not same.")
	}
	if g.IfBite != point.IfBit {
		return errors.New("ifbit not same.")
	}
	if g.IfBite {
		if g.BeginAddress != point.Address {
			return errors.New("address not same.")
		}
		maxsize = int(point.Bit - g.BeginBit)
		size := GetLength(point.Type)
		if maxsize+size > anaGroupSize {
			return errors.New("group full")
		}
		g.Size = maxsize + size
		g.pointArray = append(g.pointArray, point)
		return
	}
	maxsize = int(point.Address) - int(g.BeginAddress)
	var size int
	if point.IfStr {
		size = int(point.StrSize)
	} else {
		size = GetLength(point.Type)
	}

	if maxsize+size > anaGroupSize {
		return errors.New("group full")
	}
	g.Size = maxsize + size
	g.pointArray = append(g.pointArray, point)
	return
}

//获取点数
func (g *Group) GetCount() int {
	return len(g.pointArray)
}

//获取寄存器长度
func (g *Group) GetSize() int {
	return g.Size
}

//获取点数组
func (g *Group) GetPointArray() (array []*Point) {
	return g.pointArray
}

//-----------------------------Serial-------------------------------------------
//解析响应
func (g *Group) DoSerialResponse(data []byte) (err error) {
	t := time.Now().Unix()
	for _, point := range g.pointArray {
		if point.IfBit {
			g.ParseSerialStatueValue(data, point, t)
		} else {
			g.ParseSerialRegistValue(data, point, t)
		}
	}
	return
}

//解析开关量
func (g *Group) ParseSerialStatueValue(data []byte, point *Point, t int64) {
	address := int(int32(uint32(point.Bit))-int32(uint32(g.BeginBit))) * 2
	//logs.Debug(address)
	val, err := strconv.Atoi(string(data[address : address+2]))
	if err != nil {
		logs.Debug(err)
		return
	}
	point.Value = float64(val & 1)
	point.PtrValue = point.Value
	point.IsUpdate = true
	point.Time = int64(t)
	return
}

//解析模拟量
func (g *Group) ParseSerialRegistValue(data []byte, point *Point, t int64) {
	address := int(int32(uint32(point.Address))-int32(uint32(g.BeginAddress))) * 4
	err := ParserSerialValueByType(data, point, address, t)
	if err != nil {
		logs.Info(err)
		return
	}
}

//根据类型解析值
func ParserSerialValueByType(data []byte, point *Point, address int, t int64) (err error) {
	l := len(data)
	switch point.Type {
	case HOSTLINK_INT16:
		if address <= l-4 {
			val, err := strconv.ParseInt(string(data[address:address+4]), 16, 32)
			if err != nil {
				return err
			}
			point.Value = float64(val)
		}
	case HOSTLINK_INT16_L:
		if address <= l-4 {
			dat := append(data[address+2:address+4], data[address:address+2]...)
			val, err := strconv.ParseInt(string(dat), 16, 32)
			if err != nil {
				return err
			}
			point.Value = float64(val)
		}

	case HOSTLINK_UINT16:
		if address <= l-4 {
			val, err := strconv.ParseUint(string(data[address:address+4]), 16, 32)
			if err != nil {
				return err
			}
			point.Value = float64(val)
		}
	case HOSTLINK_UINT16_L:
		if address <= l-4 {
			dat := append(data[address+2:address+4], data[address:address+2]...)
			val, err := strconv.ParseUint(string(dat), 16, 32)
			if err != nil {
				return err
			}
			point.Value = float64(val)
		}
	case HOSTLINK_INT32: //2143
		if address <= l-8 {
			vStr := string(data[address : address+8])
			vStr = vStr[4:6] + vStr[6:8] + vStr[:2] + vStr[2:4]
			vByte, err := hex.DecodeString(vStr)
			if err != nil {
				return err
			}
			point.Value = float64(int32(binary.BigEndian.Uint32(vByte)))
		}
	case HOSTLINK_INT32_H:
		if address <= l-8 {
			vByte, err := hex.DecodeString(string(data[address : address+8]))
			if err != nil {
				return err
			}
			point.Value = float64(int32(binary.BigEndian.Uint32(vByte)))
		}
	case HOSTLINK_INT32_L:
		if address <= l-8 {
			vStr := string(data[address : address+8])
			vByte, err := hex.DecodeString(vStr)
			if err != nil {
				return err
			}
			point.Value = float64(int32(binary.LittleEndian.Uint32(vByte)))
		}
	case HOSTLINK_UINT32:
		if address <= l-8 {
			vStr := string(data[address : address+8])
			vStr = vStr[4:6] + vStr[6:8] + vStr[:2] + vStr[2:4]
			vByte, err := hex.DecodeString(vStr)
			if err != nil {
				return err
			}
			point.Value = float64(binary.BigEndian.Uint32(vByte))
		}
	case HOSTLINK_UINT32_H:
		if address <= l-8 {
			vByte, err := hex.DecodeString(string(data[address : address+8]))
			if err != nil {
				return err
			}
			point.Value = float64(binary.BigEndian.Uint32(vByte))
		}
	case HOSTLINK_UINT32_L:
		if address <= l-8 {
			vStr := string(data[address : address+8])
			vByte, err := hex.DecodeString(vStr)
			if err != nil {
				return err
			}
			point.Value = float64(binary.LittleEndian.Uint32(vByte))
		}
	case HOSTLINK_FLOAT:
		if address <= l-8 {
			vStr := string(data[address : address+8])
			vStr = vStr[4:6] + vStr[6:8] + vStr[:2] + vStr[2:4]
			vByte, err := hex.DecodeString(vStr)
			if err != nil {
				return err
			}
			vUint32 := binary.BigEndian.Uint32(vByte)
			point.Value = float64(math.Float32frombits(vUint32))
		}
	case HOSTLINK_FLOAT_H:
		if address <= l-8 {
			vStr := string(data[address : address+8])
			vByte, err := hex.DecodeString(vStr)
			if err != nil {
				return err
			}
			vUint32 := binary.BigEndian.Uint32(vByte)
			point.Value = float64(math.Float32frombits(vUint32))
		}
	case HOSTLINK_FLOAT_L:
		if address <= l-8 {
			vStr := string(data[address : address+8])
			vByte, err := hex.DecodeString(vStr)
			if err != nil {
				return err
			}
			vUint32 := binary.LittleEndian.Uint32(vByte)
			point.Value = float64(math.Float32frombits(vUint32))
		}
	default:
		err = errors.New("data type error")
		t = 0
		return err
	}
	point.IsUpdate = true
	point.Time = int64(t)
	return

}

//-----------------------------TCP/UDP------------------------------------------
//解析响应
func (g *Group) DoIPResponse(data []byte) (err error) {
	t := time.Now().Unix()
	for _, point := range g.pointArray {
		if point.IfBit {
			g.ParseIPStatueValue(data, point, t)
		} else {
			g.ParseIPRegistValue(data, point, t)
		}
	}
	return
}

//解析开关量
func (g *Group) ParseIPStatueValue(data []byte, point *Point, t int64) {
	address := int(point.Bit) - int(g.BeginBit)
	if address <= len(data)-1 {
		point.Value = float64(uint(data[address]) & 1)
		point.Time = t
		point.IsUpdate = true
		point.PtrValue = point.Value
	}
	return
}

//解析模拟量
func (g *Group) ParseIPRegistValue(data []byte, point *Point, t int64) {
	address := int(point.Address-g.BeginAddress) * 2
	err := ParseIPValueByType(data, point, address, t)
	if err != nil {
		logs.Error(err)
		return
	}
	return
}

//根据类型解析值
func ParseIPValueByType(data []byte, point *Point, address int, t int64) (err error) {
	l := len(data)
	switch point.Type {
	case HOSTLINK_INT16:
		if address <= l-2 {
			point.Value = float64(int16(binary.BigEndian.Uint16(data[address:])))
		}
	case HOSTLINK_INT16_L:
		if address <= l-2 {
			value := uint(data[address]) |
				uint(data[address+1])
			point.Value = float64(int16(value))
		}
	case HOSTLINK_UINT16:
		if address <= l-2 {
			point.Value = float64(binary.BigEndian.Uint16(data[address:]))
		}
	case HOSTLINK_UINT16_L:
		if address <= l-2 {
			value := uint(data[address]) |
				uint(data[address+1])
			point.Value = float64(value)
		}
	case HOSTLINK_INT32: //2143//cdab
		if address <= l-4 {
			value := uint(data[address])<<8 |
				uint(data[address+1]) |
				uint(data[address+2])<<24 |
				uint(data[address+3])<<16
			point.Value = float64(int32(value))
		}
	case HOSTLINK_INT32_L:
		if address <= l-4 {
			point.Value = float64(int32(binary.LittleEndian.Uint32(data[address:])))
		}

	//add by shouchun.ji
	case HOSTLINK_INT32_H:
		if address <= l-4 {
			point.Value = float64(int32(binary.BigEndian.Uint32(data[address:])))
		}

	case HOSTLINK_UINT32: //2143
		if address <= l-4 {
			value := uint(data[address])<<8 |
				uint(data[address+1]) |
				uint(data[address+2])<<24 |
				uint(data[address+3])<<16

			point.Value = float64(value)
		}
	case HOSTLINK_UINT32_H:
		if address <= l-4 {
			point.Value = float64(binary.BigEndian.Uint32(data[address:]))
		}
	case HOSTLINK_UINT32_L:
		if address <= l-4 {
			point.Value = float64(binary.LittleEndian.Uint32(data[address:]))
		}

	case HOSTLINK_FLOAT_H: //4321
		if address <= l-4 {
			value := uint32(
				uint(data[address])<<24 |
					uint(data[address+1])<<16 |
					uint(data[address+2])<<8 |
					uint(data[address+3]),
			)
			point.Value = float64(math.Float32frombits(value)) //将4字节无符号整数每位不变，转换成float32值
		}
	case HOSTLINK_FLOAT_L: //1234
		if address <= l-4 {
			value := uint32(uint(data[address]) |
				uint(data[address+1])<<8 |
				uint(data[address+2])<<16 |
				uint(data[address+3])<<24,
			)

			point.Value = float64(math.Float32frombits(value))
		}

	case HOSTLINK_FLOAT: //2143
		if address <= l-4 {
			value := uint32(uint(data[address])<<8 |
				uint(data[address+1]) |
				uint(data[address+2])<<24 |
				uint(data[address+3])<<16,
			)
			point.Value = float64(math.Float32frombits(value))
		}
	case HOSTLINK_UINT64_H, HOSTLINK_INT64_H: //64位做打包点处理
		if address <= l-8 {
			value := int64(uint64(data[address]<<56) |
				uint64(data[address]<<48) |
				uint64(data[address]<<40) |
				uint64(data[address]<<32) |
				uint64(data[address]<<24) |
				uint64(data[address]<<16) |
				uint64(data[address]<<8) |
				uint64(data[address]),
			)
			point.PtrValue = value
		}
	default:
		point.Time = 0
		return
	}
	if point.Type != HOSTLINK_UINT64_H && point.Type != HOSTLINK_INT64_H {
		point.PtrValue = point.Value
	}
	point.IsUpdate = true
	point.Time = t
	return
	return
}

//=============================Group============================================
